home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-04-11 | 46.1 KB | 1,288 lines |
-
-
-
- Archive-name: Solaris2/porting-FAQ
- Last-modified: Thursday, Feburary 23, 1995
- Version: 2.22
-
- Solaris 2 Porting FAQ
- [Last modified: 23 Feburary 1995]
-
- This article contains the answers to some Frequently Asked
- Questions (FAQ) often seen in comp.unix.solaris that relate to
- porting BSD/Solaris 1 applications to Solaris 2. Over the first
- few days of its existence, it has evolved into a more general
- discussion about portability among Unix systems, especially as it
- relates to BSD, ANSI, POSIX, and SVID compliant systems. It is
- hoped that this document will help reduce volume in this
- newsgroup and to provide hard-to-find information of general
- interest.
-
- Please redistribute this article!
-
- This FAQ is maintained by David Meyer (meyer@ns.uoregon.edu).
- Send updates and corrections to me at this address. It would
- help if the subject line contained the phrase "FAQ".
-
- This article includes answers to the following questions. Ones
- marked with a + indicate questions new to this issue; those with
- changes of content since the last issue are marked by *:
-
- 0) Which preprocessor symbols to use?
- 1) Some Include File Issues
- 2) Libraries
- 3)* Possible ANSI/POSIX/SVR4 replacements for some popular BSD functions
- 4) Signal Primer
- 5) Waiting for Children to Exit
- 6) Dealing with Shadow Password Files
- 7)* Some Compatibility Problems
- 8) Other Resources
-
- -----------------------------------------------------------------------------
- 0) TOPIC: Which preprocessor symbols to use?
-
- [Last modified: 11 October 93]
-
- [Editor's Note: This section began life as a Solaris 1 and
- Solaris 2 centric discussion. However, it has grown into a more
- generalized portability discussion. I believe that this is a
- useful discussion, but it appears that contrasting styles,
- preferences, and requirements will make consensus difficult. DM]
-
- Answer: This is a difficult and controversial question.
-
- In order to understand the following discussion, we need to be
- aware of the following standards:
-
- ANSI C (ANSI X3J11)
-
- This is the standard C definition, originally adopted as
- American National Standard X3.159-1989 and has since been
- adopted as international standard ISO/IEC 9899:1990.
-
-
- POSIX.1 (IEEE 1003.1-1990)
-
- POSIX.1, the Portable Operating System Interface for
- Computer Environments, is a system level API that deals
- with the function and format of system calls and
- utilities such as signal handling.
-
- SVID3
-
- SVID3, the System V Interface Definition Issue 3, is is
- fully compliant with POSIX.1, and is a arguably subset of
- the SVR4 system API. For example, SVID3 doesn't have
- "-ldl", but many people consider it of the SVR4 API. That
- is, a system could be SVID3-compliant without necessarily
- being an SVR4 system.
-
- XPG
-
- XPG, X/Open Company Ltd's X/Open Portability Guide, is a
- broad document which covers a great number of areas,
- including operating systems and programming languages,
- system interfaces, and internetworking. The latest
- version, XPG4, groups these components into "profiles",
- which are packaged together according to market needs.
-
-
- Two additional standards are relevant for Suns:
-
- SCD 2.0 and x86 ABIs
-
- SCD 2.0 is the SPARC Compliance Definition 2.0. The SCD
- has two components: On the hardware side,
-
- (i). System Compliance Test verifies that the hardware
- and operating system successfully emulates what
- Sun is doing. It covers low level system issues
- such as alignment, and linking and loading.
-
- (ii). The SPARC Application Verifier tests software to
- be sure that it runs on SCD hardware.
-
-
- As an example of subtle differences that exist between the BSD
- interface and SVID/POSIX standards, consider the BSD mktemp(3)
- call. The SunOS 4.1 mktemp() replaced the trailing X characters
- with the letter (e.g., X) and the current process ID. The SVID
- and SVR4 versions specify only that the six trailing Xs be
- replaced with a character string that can be used to create a
- unique filename, and does not depend on the specific name of the
- file. Thus, the BSD and SVR4/SVID3 versions are only
- semantically equivalent in the case where only the application
- cares that the filename is unique.
-
- Now, the basic philosophical question of which preprocessor
- contstucts to use here would appear to revolve around the
- following choices:
-
- (i). Use a high level, large grained standard
- definition (e.g., _POSIX_SOURCE). In this case,
- features are implicitly defined. One problem with
- such definitions is that they may cause other
- useful functions to become unavailable. However,
- there are several such definitions in common use.
- For operating systems, we have
-
- SVR4
- SYSV
- BSD
- OSF1
-
- to name a few. For standards, we are mainly
- interested interested symbols such as
-
- __STDC__
- _POSIX_SOURCE
- _XOPEN_SOURCE
-
-
- This method is not without pitfalls. For
- example, the Sun SC2.0.1 compiler defines
- __STDC__ as 0 when compiling in transition mode
- (-Xt), only setting it to 1 when the strict ANSI
- mode (-Xc) is used. The expression
-
- #if (__STDC__ - 0 == 0)
-
- can be used to recognize strict v. transition
- ANSI modes. On Solaris 2, if you compile with
- -Xc, you will lose all non-ANSI functionality.
- However, you can define _POSIX_SOURCE or
- _XOPEN_SOURCE to get a POSIX or XOPEN
- environment.
-
- If you use _POSIX_SOURCE, .eg.,
-
- #define _POSIX_SOURCE 1
-
- then all symbols not defined by Standard C or the
- POSIX standard will be hidden (except those with
- leading underscores). If you wish to use
- _POSIX_SOURCE, be sure to define it before
- including any standard header files, and avoid
- name clashes by not defining any symbols that
- begin with "_" (Similarly, note that almost all
- names beginning with "E" are reserved by
- errno.h, and many names prefixed by "va_"
- reserved by stadarg.h).
-
- One more note on _POSIX_SOURCE: SunOS 5.3 has
- introduced the new header file <sys/feature_tests.h>.
- This file is included in all files which have
- _POSIX_SOURCE dependancies.
-
- A new symbol, _POSIX_C_SOURCE was introduced in POSIX.2
- (V1 P720, L51) as a mechanism to enable POSIX.1 and
- POSIX.2 symbols. Its values are as follows:
-
- /*
- * Values of _POSIX_C_SOURCE
- *
- * undefined not a POSIX compilation
- * 1 POSIX.1-1990 compilation
- * 2 POSIX.2-1992 compilation
- * 1993xxL POSIX.4-1993 compilation
- */
-
-
- This means that POSIX.2 says that a value of 1 = POSIX.1
- and a value of 2 = POSIX.1 & POSIX.2. The idea here is
- to provide a single control point over the POSIX namespace,
- rather than having to edit each file individually.
-
- Another potential portability pitfall is the
- __svr4__ feature defined by the FSF (gcc). If you
- depend on __svr4__, you may lose portability.
- gcc also defines sun if you don't give the -ansi
- argument. If you use -ansi, then sun is not
- defined and __sun__ is.
-
- Finally, complexity may arise surrounding a
- feature which may be part of some vendor's
- version of some system Y, but may also exist in
- non-Y compliant systems. Consider, for example,
- shadow passwording. Systems conforming to the
- latest SVID (e.g., SVR4) have shadow.h, but there
- are many systems that have shadow.h without
- conforming to the SVID.
-
- So, in general, for code that uses a STD_FEATURE and
- runs on systems W, Y, and Z, you are left with
- something that may look like
-
- #if defined(W) ||
- (defined(Y) && _Y_VERSION_ > 3) ||
- (defined(Z) || defined(__Z__))
- #include <STD_FEATURE.h>
- #endif
-
- [W, Y, Z are things like SVR4, AIX, NeXT, BSD,
- and so on. STD_FEATURE.h is something like shadow.h]
-
- This example exposes two problems the large
- grained method. First, it forces one to keep
- track of exactly which vendors supply
- <STD_FEATURE.h>. Second, the complexity of the
- preprocessor expressions may be a serious
- consideration, since their complexity is
- something like
-
- O(n*m) where
-
- n = the number of standard features, and
- m = number of vendors/systems
-
-
- (ii). Define new fine-grained feature tests (e.g.,
- HAVE_POSIX_SIGNALS, or HAVE_SHADOW_H) for
- features of interest. Such fine-grained features
- could be used in conjunction with large grained
- definitions. An nice example of using feature
- definitions is the GNU configure program. It
- uses, for example, the features HAVE_BCOPY and
- HAVE_MEMSET to enable either the bcopy (BSD) or
- memset (ANSI) functions.
-
- Feature testing has the advantage of being useful
- for automatic configuration with programs such as
- GNU configure. GNU configure outputs statements
- of the form
-
-
- #define HAVE_aaaa
- #define HAVE_bbbb
- #define HAVE_cccc
- ....
-
- Another way to generate a feature set is by
- using the symbol defining the system, e.g.,
-
- #ifdef SVR4
- #define HAVE_aaaa
- #define HAVE_bbbb
- #define HAVE_cccc
- ....
-
- #endif
- #ifdef BSD43
- #define HAVE_yyyy
- ...
- #endif
- #ifdef NEWTHING
- #define HAVE_zzzz
- ...
- #endif
-
- Feature testing also helps to avoid constructs
- such as
-
- #if defined(_POSIX_SOURCE) || defined(_XOPEN_SOURCE)
-
- [Editor's Note: Finally, an observation: The real
- issue here appears to be how many of these
- "features" are migrating to the standard
- operating systems and interfaces, and how many
- vendors are implementing these standards. In
- general, some people feel that feature testing
- improves portability (and readability), and
- others believe that the feature testing style
- decreases portability and readability. DM]
-
-
- (iii). Use some part of the feature's definition itself
- to enable the feature, for example
-
- #ifdef _IOLBF
- setvbuf(stderr, NULL, _IOLBF, 0);
- #else
- setlinebuf(stderr);
- #endif /* _IOLBF */
-
- Note that in this case, another, possibly better
- option is (consider the case in which some vendor
- has inadvertently defined _IOLBF for some other
- purpose):
-
- #ifdef __STDC__
- setvbuf(stderr, NULL, _IOLBF, 0);
- #else
- setlinebuf(stderr);
- #endif /* __STDC__ */
-
- since setvbuf is required by Standard C.
-
-
-
- Finally, some people have suggested the use of
- expressions like
-
- #if defined(sun) && defined(__svr4__)
- <Solaris 2 centric code>
- #else
- ...
- #endif
-
-
- As noted above, the __svr4__ feature is defined by the
- FSF (gcc). If you depend on __svr4__, you may lose
- portability. gcc also defines sun if you don't give the
- -ansi argument. If you use -ansi, then sun is not
- defined and __sun__ is. The implication here is that
- depending on symbols defined by a given compiler can
- reduce portability.
-
- In general, such a construct should be used if and only if
- the code in question cannot be covered by some standard
- (e.g., SVR4, _POSIX_SOURCE, etc.). Note that it is also
- compiler specific.
-
-
- -----------------------------------------------------------------------------
- 1) TOPIC: Include File Issues
-
- [Last modified: 19 August 93]
-
- The first and apparently most common problem is that
- /usr/include/strings.h is not ANSI compliant, and as such does not
- exist on Solaris 2 (or SVR4). It should be replaced by
- /usr/include/string.h, e.g. (following GNU feature definition
- conventions)
-
- #if HAVE_STRING_H || defined(STDC_HEADERS)
- #include <string.h>
- #else
- #include <strings.h>
- #endif
- #if defined(STDC_HEADERS)
- #include <stdlib.h>
- #endif /* HAVE_STRING_H */
-
- while ANSI-C requires the name be string.h, one might
- define this as
-
- #ifdef __STDC__
- #include <string.h>
- #else
- #include <strings.h>
- #endif /* __STDC__ */
-
- However, this again neglects the case in which the vendor
- provides string.h in a non-ANSI environment.
-
-
- Another thing to watch is for the symbols O_CREAT, O_TRUNC, and
- O_EXCL being undefined. On BSD systems, these are defined in
- <sys/file.h>. On Solaris 1 systems (beginning with SunOS 4.0) ,
- these are defined in <sys/fnctlcom.h> (which is included in
- <sys/file.h>). On a POSIX compliant system, these symbols are
- defined in <fcntl.h>, which is not included in <sys/file.h>.
- Since <fcntl.h> is defined on SunOS 4.1.x, replacing <sys/file.h>
- with <fcntl.h> works for both SunOS 4.1.x and SVR4. See, for
- example, section 5.3.1.1 of the POSIX spec.
-
-
- -----------------------------------------------------------------------------
-
- 2) TOPIC: Libraries
-
- [Last modified: 12 Feburary 94]
-
- Network Libraries:
-
- Many of the network functions and definitions that were present
- in the BSD libc are now in libnsl.so and libsocket.so. Thus
- networking code will generally need to be linked with -lsocket
- -lnsl. Since libsocket.so requires libnsl.so (it is NEEDED), you must
- specify them in this order. Note that you need libnsl.so for functions
- like gethostbyname (see gethostbyname note below). Incidently, you can
- look at selected parts of an object file using dump(1), e.g.,
-
- % dump -Lv /usr/lib/libsocket.so
-
- /usr/lib/libsocket.so:
-
- **** DYNAMIC SECTION INFORMATION ****
- .dynamic :
- [INDEX] Tag Value
- [1] NEEDED libnsl.so.1
- [2] INIT 0x3174
-
- [...]
-
- Regular Expressions
-
- Another problem frequently encountered is that the regexp
- functions (see regexpr(3G)) are not defined in libc. On Solaris
- 2, you must link with libgen.a (-lgen) in order to get these
- definitions. See Intro(3) for a more complete discussion.
-
- Name List (nlist)
-
- You must link with libelf.a (-lelf) to get the nlist(3E)
- definition.
-
- -----------------------------------------------------------------------------
-
- 3)* TOPIC: Possible ANSI/POSIX/SVR4 replacements for some popular
- BSD functions
-
- [Last modified: 23 Feburary 1995]
-
- [Editor's Note: Once again, this section began life a SunOS 4.1.x
- and SunOS 5.x centric discussion. It too has grown into a
- discussion dealing with general portability for BSD to other
- standards. DM]
-
- Problems finding functions that were defined in the BSD libc.a is
- one of the most frequently asked porting questions. The following
- table and code fragments suggest substitutes for some common BSD
- constructs (more complete lists can be found in some of the texts
- listed in section 7 below).
-
- In addtion to the possibilites listed below, many people have
- created compatability libraries using GNU autoconfigure. An
- example of this is the "generic" libary from Dan Stromberg
- (strombrg@hydra.acs.uci.edu). It can be found on
- ftp.uci.edu:/pub/generic/generic.tar.gz.
-
-
- BSD Possibilities Standards/Notes
- ============================================================================
- srandom(seed) srand(seed) ANSI-C (Also, some older UNIX)
- srand48(seed) SVR4
-
- non-ANSI signal() sigset() SVR4 (systems calls not
- (e.g., SunOS) restarted, but bytes r/w
- returned, else EINTR)
- sigaction POSIX (but extensible by
- implementation)
-
- sigvec sigaction POSIX
- sigblock sigprocmask POSIX
- sigset(.., SIG_HOLD)
- sighold SVR4
- sigsetmask sigprocmask POSIX
- sigset/sigrelse SVR4
-
- sigpause sigsuspend POSIX
-
- setjmp sigsetjmp POSIX
- longjmp siglongjmp POSIX
-
- statfs statvfs SVR4
-
- bcopy memmove ANSI-C (BSD bcopy() handles
- overlapping areas
- correctly, as does
- memmove, but not memcpy)
-
- bzero memset ANSI-C
-
- index strchr ANSI-C
- rindex strrchr ANSI-C
-
- getwd getcwd POSIX
-
- getrusage open,ioctl The getrusage information
- (and a whole lot more) can be
- found in the prusage structure.
- Use the PIOCUSAGE ioctl. See
- the example below and the
- proc(4) man page for detail.
-
-
- gethostname sysinfo(SI_HOSTNAME,..) SVR4 See sysinfo(2) for
- many other possible
- values
-
- getdtablesize sysconf(_SC_OPEN_MAX) POSIX See sysconf(3C) for
- many other values
- available via sysconf.
-
- strptime See code from Kevin Ruddy
- below
-
- timelocal mktime
-
- wait3 w/o rusage waitpid POSIX
- wait3 waitid SVR4
-
- usleep nanosleep POSIX See nanosleep(3R) on
- Solaris 2.3 (see libposix4.a)
- For a Solaris 2.[0-2], see the
- example below.
-
-
-
-
- ------------------------------------------------------------------
-
- Some Well-Traveled Macros
- -------------------------
-
- #define bcopy(src,dest,len) (memmove((dest), (src), (len)))
- #define bzero(dest,len) (memset((dest), (char)0, (len)))
- #define bcmp(b1,b2,n) (memcmp((b1),(b2),(n)))
- #define index(s,c) strchr((s),(c))
- #define rindex(s,c) strrchr((s),(c))
- #define MIN(a, b) ((a) < (b) ? (a) : (b))
- #define MAX(a, b) ((a) < (b) ? (b) : (a))
- #ifdef MAXPATHLEN
- #define getwd(x) getcwd((x), MAXPATHLEN)
- #endif /* MAXPATHLEN */
- define setlinebuf(fp) setvbuf(fp, NULL, _IOLBF, 0);
-
-
- Timing Problems
- ---------------
-
- POSIX defines the <sys/times.h> function for subsecond
- timing. Sun seems to provide about 1/60 second accuracy.
-
- #include <stdio.h>
- #include <sys/times.h> /* for struct tms and times() */
- #include <time.h> /* for CLK_TCK value */
-
- int main(void) {
- struct tms tms_start, tms_finish; /* user and system time */
- clock_t start, finish; /* real time */
- start = times( &tms_start );
- /* ... do something ... */
- finish = times( &tms_finish );
- printf("(in seconds) %f real, %f system, %f user\n",
- (finish-start) / (double)CLK_TCK,
- (tms_finish.tms_stime-tms_start.tms_stime) / (double)CLK_TCK,
- (tms_finish.tms_utime-tms_start.tms_utime) / (double)CLK_TCK);
- return 0;
- }
-
- You might want to divide CLK_TCK by 1000.0 to get more
- precise millisecond values. times() returns -1 if it
- cannot provide timing information.
-
- While Solaris 2 conforms to POSIX, SunOS 4.1 defines
- times() as returning a flag instead of elapsed real time.
- You can use ftime() to get elapsed real time:
-
- #include <stdio.h>
- #include <sys/types.h> /* for time_t */
- #include <sys/timeb.h> /* for ftime() and struct timeb */
-
- int main(void) {
- struct timeb start, finish;
- double real_secs;
- ftime( &start );
- /* ... do something ... */
- ftime( &finish );
- real_secs = finish.time - start.time;
- if ( finish.millitm < start.millitm )
- real_secs = (real_secs-1) +
- (1000+start.millitm-finish.millitm)/1000.0;
- else
- real_secs = (finish.millitm-start.millitm)/1000.0;
- printf( "That took %f real seconds.", real_secs );
- return 0;
- }
-
- The ANSI C function clock() can also be used for timing.
- It returns elased "processor" time, which is equivalent
- to system+user time. While it also returns a clock_t
- value, you must divide the difference between to calls to
- clock() by CLOCKS_PER_SEC, *not* CLK_TCK. The values are
- different by orders of magnitude. SunOS 4.1 doesn't seem
- to provide CLOCKS_PER_SEC or CLK_TCK in <time.h>. Try
- 10000000 and 60, respectively.
-
-
-
- Compatibility Functions
- -----------------------
-
- /*
- * getrusage --
- */
-
- #include <sys/resource.h>
- #ifndef RUSAGE_SELF
- #include <sys/procfs.h>
- #endif
-
- #ifdef PIOCUSAGE
- int fd;
- char proc[SOMETHING];
- prusage_t prusage;
-
- sprintf(proc,"/proc/%d", getpid());
- if ((fd = open(proc,O_RDONLY)) == -1) {
- perror("open");
- ....
- }
- if (ioctl(fd, PIOCUSAGE, &prusage) == -1) {
- perror("ioctl");
- ...
- }
- ....
- #else /* Again, assume BSD */
- if (getrusage(RUSAGE_SELF, &rusage) == -1) {
- perror("getrusage");
- ....
- }
- ....
- #endif /* PIOCUSAGE */
-
-
-
- /*
- * setlinebuf --
- *
- */
-
- #ifdef __STDC__
- setvbuf(stderr, NULL, _IOLBF, 0);
- #else
- setlinebuf(stderr);
- #endif /* __STDC__ */
-
-
- /*
- * gethostid
- *
- * This example has a combination of high-level
- * (SVR4) and (SI_HW_SERIAL) feature declarations.
- */
-
- #if defined(SVR4) && defined(SI_HW_SERIAL)
- long gethostid() {
-
- char buf[128];
-
- if (sysinfo(SI_HW_SERIAL, buf, 128) == -1) {
- perror("sysinfo");
- exit(1);
- }
- return(strtoul(buf,NULL,0));
- }
- #endif /* SVR4 && SI_HW_SERIAL */
-
-
- /*
- * getdtablesize --
- *
- * Several possibilites here. Note that while one
- * can emulate getdtablesize with getrlimit on SVR4
- * or 4.3BSD (or later), these systems should be
- * POSIX.1 compliant, so sysconf is preferred.
- *
- */
-
- #ifdef _SC_OPEN_MAX /* POSIX -- preferred */
- if ((tableSize = sysconf(_SC_OPEN_MAX)) == -1) {
- perror("sysconf");
- ...
- }
- #elif RLIMIT_NOFILE /* who is non POSIX but has this? */
- if (getrlimit(RLIMIT_NOFILE, &rlimit) == -1) {
- perror("getrlimit");
- exit(1);
- }
- tableSize = rlimit.rlim_max;
- #else /* assume old BSD type */
- tableSize = getdtablesize();
- #endif
-
-
- ------------------
-
- /*
- * gethostname --
- *
- */
-
- #ifdef SVR4
- #include <sys/systeminfo.h>
- #endif /* SVR4 */
-
- ....
-
- char buf[MAXHOSTNAME]
-
- #ifdef SVR4
- if (sysinfo(SI_HOSTNAME, buf, sizeof(buf)) <0) {
- perror("SI_HOSTNAME");
- exit(BAD);
- }
- #else /* Assume BSD */
- if (gethostname(buf, sizeof(buf)) < 0) {
- perror("gethostname");
- exit(BAD);
- }
- #endif /* SVR4 */
-
- /* buf has hostname here... */
-
-
- /*
- * usleep(delay) --
- *
- * Possible usleep replacement. Delay in microseconds.
- * Another possiblity is to use poll(2). On Solaris
- * 2.x, select is just a wrapper for poll, so you
- * are better off using it directly. If you use,
- * poll, note that it uses millisecond resolution,
- * and is not affected by the O_NDELAY and O_NONBLOCK
- * flags.
- *
- * Note that using nanosleep has portability implications,
- * even across different versions of Solaris 2.x. In
- * particular, only Solaris 2.3 has libposix4, and
- * hence nanosleep. Select (or poll) is a better option if
- * you need portability across those versions.
- *
- * If you define USE_NANOSLEEP, be sure to link with -lposix4
- *
- */
-
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <errno.h>
- #include <time.h>
- #include <sys/time.h>
- #include <sys/param.h>
- #include <sys/types.h>
- #ifdef USE_POLL
- #include <stropts.h>
- #include <poll.h>
- #endif /* USE_POLL */
-
- int usleep(unsigned long int useconds)
- {
- #ifdef USE_NANOSLEEP
- struct timespec rqtp;
-
- rqtp.tv_sec = useconds / (unsigned long) 1000000;
- rqtp.tv_nsec = (useconds % (unsigned long) 1000000) * 1000 ;
-
- if (nanosleep(&rqtp, (struct timespec *) NULL) == -1)
- perror("nanosleep");
- return (0);
-
- #elif USE_POOL
- struct pollfd unused;
-
- if (poll(&unused,0,(useconds/1000)) == -1)
- perror("poll");
- return(0);
- #elif USE_USLEEP
- struct timeval delay;
-
- delay.tv_sec = 0;
- delay.tv_usec = useconds;
- if (select(0,
- (fd_set *) NULL,
- (fd_set *) NULL,
- (fd_set *) NULL,
- &delay) == -1)
- perror("select");
- return (0);
- #endif /* USE_NANOSLEEP */
-
-
- /*
- * tzsetwall --
- */
-
- void tzsetwall()
- {
- unsetenv("TZ");
- tzset();
- }
-
- /*
- * gethostybname --
- *
- * The following code was contributed by Casper H.S. Dik
- * to address the following problem:
- *
- * gethostbyname() always returns null in h->aliases.
- * Now, gethostbyX can be replaced its __switch_gethostbyX
- * equivalents. However, these are missing from Solaris 2.3.
- *
- * The _r functions are reentrant. They have a different
- * calling sequence. (The __switch_getXXXbyYYY are called
- * like getXXXbyYYY, the _switch_getXXXbyYYY_r are called
- * like getXXXbyYYY_r)
- *
- * With this bit of knowledge I constructed the code that
- * follows this message. Just plug it in every program
- * that requires gethostbyname to work. (Gethostbyaddr()
- * is added for symmetry).
- *
- * You'll need to link with -lnsl -ldl.
- *
- * It works for Solaris 2.2 and 2.3. (Compiled on 2.3 or
- * 2.2 it will run 2.2 and 2.3)
- *
- * Note that as with __switch* _switch*_r is undocumented
- * and can be changed in the next release.
- *
- */
-
- /*
- * Proper gethostbyXX function for Solaris 2.0-2.3
- * (and later ?)
- *
- * Fixed in 2.4?
- *
- * You'll need -ldl added to the link command line.
- *
- * Casper Dik (casper@fwi.uva.nl)
- *
- */
-
- #include <netdb.h>
- #include <dlfcn.h>
-
- #define HBUFSIZE 4096
-
- static void *dlhandle;
- /* The gethostbyXXX function variables. Named after
- * then .so files they appear in. nsw*.so in SunOS 5.2
- * and earlier, nss_*.so in 5.3 */
- static struct hostent *(*nswghba)(const char *, int, int),
- *(*nswghbn)(const char *),
- *(*nss_ghba)(const char *,
- int, int,
- struct hostent *, char *, int, int *),
- *(*nss_ghbn)(const char *,
- struct hostent *, char *, int, int *);
-
- static int dlinit(void)
- {
- static int dlstatus = 0; /* 0 = uninited, 1 = inited & ok, -1 = error */
-
- if (dlstatus)
- return dlstatus;
-
- dlstatus = -1;
-
- dlhandle = dlopen(0, RTLD_LAZY);
-
- if (dlhandle == 0)
- return dlstatus;
-
- /* SunOS 5.0 - 5.2 */
- nswghba = (struct hostent *(*)(const char *, int, int))
- dlsym(dlhandle, "__switch_gethostbyaddr");
-
- nswghbn = (struct hostent *(*)(const char *))
- dlsym(dlhandle, "__switch_gethostbyname");
-
- /* either both should exist or both should not exist */
- if ((nswghbn == 0) != (nswghba == 0))
- return dlstatus;
-
- if (nswghbn)
- return dlstatus = 1;
-
- /* SunOS 5.3 - ? */
- nss_ghba = (struct hostent *(*)
- (const char *, int, int, struct hostent *, char *, int , int *))
- dlsym(dlhandle, "_switch_gethostbyaddr_r");
-
- nss_ghbn = (struct hostent *(*)
- (const char *, struct hostent *, char *, int , int *))
- dlsym(dlhandle, "_switch_gethostbyname_r");
-
- /* these two must exist when we get here */
- if (nss_ghbn != 0 && nss_ghba != 0)
- dlstatus = 1;
-
- return dlstatus;
- }
-
- struct hostent *
- gethostbyname(const char *name) {
-
- static struct hostent hp;
- static char buf[HBUFSIZE];
-
- if (dlinit() == -1)
- return 0;
-
- if (nswghbn)
- return nswghbn(name);
- else
- return nss_ghbn(name, &hp, buf, sizeof(buf), &h_errno);
- }
-
- struct hostent *
- gethostbyaddr(const char *addr, int len, int type) {
- static struct hostent hp;
- static char buf[HBUFSIZE];
-
- if (dlinit() == -1)
- return 0;
-
- if (nswghba)
- return nswghba(addr, len, type);
- else
- return nss_ghba(addr,
- len, type, &hp, buf, sizeof(buf), &h_errno);
- }
-
-
- ------------------
- strptime
- -----------------
-
- /*
- * Copyright (c) 1994 Powerdog Industries. All rights reserved.
- *
- * Redistribution and use in source and binary forms, without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgement:
- * This product includes software developed by Powerdog Industries.
- * 4. The name of Powerdog Industries may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
- #ifndef lint
- static char copyright[] =
- "@(#) Copyright (c) 1994 Powerdog Industries. All rights reserved.";
- static char sccsid[] = "@(#)strptime.c 0.1 (Powerdog) 94/03/27";
- #endif /* not lint */
-
- #include <time.h>
- #include <ctype.h>
- #include <locale.h>
- #include <string.h>
-
- #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
-
- #ifndef sun
- struct dtconv {
- char *abbrev_month_names[12];
- char *month_names[12];
- char *abbrev_weekday_names[7];
- char *weekday_names[7];
- char *time_format;
- char *sdate_format;
- char *dtime_format;
- char *am_string;
- char *pm_string;
- char *ldate_format;
- };
- #endif
-
- static struct dtconv En_US = {
- { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" },
- { "January", "February", "March", "April",
- "May", "June", "July", "August",
- "September", "October", "November", "December" },
- { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" },
- { "Sunday", "Monday", "Tuesday", "Wednesday",
- "Thursday", "Friday", "Saturday" },
- "%H:%M:%S",
- "%m/%d/%y",
- "%a %b %e %T %Z %Y",
- "AM",
- "PM",
- "%A, %B, %e, %Y"
- };
-
- #ifdef SUNOS4
- extern int strncasecmp();
- #endif
-
- char *
- strptime(char *buf, char *fmt, struct tm *tm)
- {
- char c,
- *ptr;
- int i,
- len;
-
- ptr = fmt;
- while (*ptr != 0) {
- if (*buf == 0)
- break;
-
- c = *ptr++;
-
- if (c != '%') {
- if (isspace(c))
- while (*buf != 0 && isspace(*buf))
- buf++;
- else if (c != *buf++)
- return 0;
- continue;
- }
-
- c = *ptr++;
- switch (c) {
- case 0:
- case '%':
- if (*buf++ != '%')
- return 0;
- break;
-
- case 'C':
- buf = strptime(buf, En_US.ldate_format, tm);
- if (buf == 0)
- return 0;
- break;
-
- case 'c':
- buf = strptime(buf, "%x %X", tm);
- if (buf == 0)
- return 0;
- break;
-
- case 'D':
- buf = strptime(buf, "%m/%d/%y", tm);
- if (buf == 0)
- return 0;
- break;
-
- case 'R':
- buf = strptime(buf, "%H:%M", tm);
- if (buf == 0)
- return 0;
- break;
-
- case 'r':
- buf = strptime(buf, "%I:%M:%S %p", tm);
- if (buf == 0)
- return 0;
- break;
-
- case 'T':
- buf = strptime(buf, "%H:%M:%S", tm);
- if (buf == 0)
- return 0;
- break;
-
- case 'X':
- buf = strptime(buf, En_US.time_format, tm);
- if (buf == 0)
- return 0;
- break;
-
- case 'x':
- buf = strptime(buf, En_US.sdate_format, tm);
- if (buf == 0)
- return 0;
- break;
-
- case 'j':
- if (!isdigit(*buf))
- return 0;
-
- for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
- i *= 10;
- i += *buf - '0';
- }
- if (i > 365)
- return 0;
-
- tm->tm_yday = i;
- break;
-
- case 'M':
- case 'S':
- if (*buf == 0 || isspace(*buf))
- break;
-
- if (!isdigit(*buf))
- return 0;
-
- for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
- i *= 10;
- i += *buf - '0';
- }
- if (i > 59)
- return 0;
-
- if (c == 'M')
- tm->tm_min = i;
- else
- tm->tm_sec = i;
-
- if (*buf != 0 && isspace(*buf))
- while (*ptr != 0 && !isspace(*ptr))
- ptr++;
- break;
-
- case 'H':
- case 'I':
- case 'k':
- case 'l':
- if (!isdigit(*buf))
- return 0;
-
- for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
- i *= 10;
- i += *buf - '0';
- }
- if (c == 'H' || c == 'k') {
- if (i > 23)
- return 0;
- } else if (i > 11)
- return 0;
-
- tm->tm_hour = i;
-
- if (*buf != 0 && isspace(*buf))
- while (*ptr != 0 && !isspace(*ptr))
- ptr++;
- break;
-
- case 'p':
- len = strlen(En_US.am_string);
- if (strncasecmp(buf, En_US.am_string, len) == 0) {
- if (tm->tm_hour > 12)
- return 0;
- if (tm->tm_hour == 12)
- tm->tm_hour = 0;
- buf += len;
- break;
- }
-
- len = strlen(En_US.pm_string);
- if (strncasecmp(buf, En_US.pm_string, len) == 0) {
- if (tm->tm_hour > 12)
- return 0;
- if (tm->tm_hour != 12)
- tm->tm_hour += 12;
- buf += len;
- break;
- }
-
- return 0;
-
- case 'A':
- case 'a':
- for (i = 0; i < asizeof(En_US.weekday_names); i++) {
- len = strlen(En_US.weekday_names[i]);
- if (strncasecmp(buf,
- En_US.weekday_names[i],
- len) == 0)
- break;
-
- len = strlen(En_US.abbrev_weekday_names[i]);
- if (strncasecmp(buf,
- En_US.abbrev_weekday_names[i],
- len) == 0)
- break;
- }
- if (i == asizeof(En_US.weekday_names))
- return 0;
-
- tm->tm_wday = i;
- buf += len;
- break;
-
- case 'd':
- case 'e':
- if (!isdigit(*buf))
- return 0;
-
- for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
- i *= 10;
- i += *buf - '0';
- }
- if (i > 31)
- return 0;
-
- tm->tm_mday = i;
-
- if (*buf != 0 && isspace(*buf))
- while (*ptr != 0 && !isspace(*ptr))
- ptr++;
- break;
-
- case 'B':
- case 'b':
- case 'h':
- for (i = 0; i < asizeof(En_US.month_names); i++) {
- len = strlen(En_US.month_names[i]);
- if (strncasecmp(buf,
- En_US.month_names[i],
- len) == 0)
- break;
-
- len = strlen(En_US.abbrev_month_names[i]);
- if (strncasecmp(buf,
- En_US.abbrev_month_names[i],
- len) == 0)
- break;
- }
- if (i == asizeof(En_US.month_names))
- return 0;
-
- tm->tm_mon = i;
- buf += len;
- break;
-
- case 'm':
- if (!isdigit(*buf))
- return 0;
-
- for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
- i *= 10;
- i += *buf - '0';
- }
- if (i < 1 || i > 12)
- return 0;
-
- tm->tm_mon = i - 1;
-
- if (*buf != 0 && isspace(*buf))
- while (*ptr != 0 && !isspace(*ptr))
- ptr++;
- break;
-
- case 'Y':
- case 'y':
- if (*buf == 0 || isspace(*buf))
- break;
-
- if (!isdigit(*buf))
- return 0;
-
- for (i = 0; *buf != 0 && isdigit(*buf); buf++) {
- i *= 10;
- i += *buf - '0';
- }
- if (c == 'Y')
- i -= 1900;
- if (i < 0)
- return 0;
-
-